# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: find3db_util.py
  @time: 2022/5/11 10:03
  @desc:
"""
from math import *
from tkinter import Y
import numpy as np
from scipy.signal import savgol_filter
from matplotlib import pyplot as plt


def find3db_util(x_data, y_data):
    target_x_value, target_y_value, min_x, min_peak = find_nearest_method3(x_data, y_data)
    # target_x_value, target_y_value, min_x, min_peak = find_nearest_method2(x_data, y_data)
    return target_x_value, target_y_value, min_x, min_peak


def cal_y_slope(i, y_data):
    if i > 0:
        if float(y_data[i - 1]) - float(y_data[i]) > 0 and float(y_data[i + 1]) - float(y_data[i]) < 0 and float(
                y_data[i + 2]) - float(y_data[i]) < 0 and float(y_data[i + 3]) - float(y_data[i]) < 0:
            return y_data[i]
    elif i == 0:
        if float(y_data[i + 1]) - float(y_data[i]) < 0 and float(y_data[i + 2]) - float(y_data[i]) < 0 and float(
                y_data[i + 3]) - float(y_data[i]) < 0:
            return y_data[i]


def cal_y_slope2(idx, y_data):
    if 0 < idx < len(y_data) - 1:
        if float(y_data[idx - 1]) - float(y_data[idx]) > 0 and float(y_data[idx + 1]) - float(y_data[idx]) < 0:
            return y_data[idx]
    elif idx == 0:
        if float(y_data[idx + 1]) - float(y_data[idx]) < 0 and float(y_data[idx + 2]) - float(y_data[idx]) < 0:
            return y_data[idx]


def find_nearest_method1(array, value):
    array = np.asarray(array)
    return min(array, key=lambda x: abs(x - value))


def find_nearest_method3(x_data, y_data):
    min_peak = min(y_data)
    peak_index = y_data.index(min_peak)
    length = len(y_data)
    compare_value = float(min_peak) + 3
    min_x = x_data[peak_index]
    target_x_value, target_y_value = "", ""
    result_list = {}
    difference_list = {}

    for i in range(length):
        result = float(y_data[i]) - compare_value
        if abs(result) < 1:  # 修改算法，先选出最接近的5个点，然后再看斜率是否符合
            result_list[i] = y_data[i]
            difference_list[i] = abs(result)
    values_list = sorted(difference_list.values())
    y_result = []
    idx_list = []
    for i in values_list:
        key_list = get_keys(difference_list, i)
        for j in key_list:
            if j not in idx_list:
                result = cal_y_slope2(j, y_data)
                if result:
                    idx_list.append(j)
                    y_result.append(result)
    if y_result:
        values = [x_data[idx_list[0]], y_result[0], min_x, min_peak]
        if check_not_none(values):
            return x_data[idx_list[0]], y_result[0], min_x, min_peak
        else:
            return None, None, None, None
    else:
        return None, None, None, None


def check_not_none(values: list):
    return all([True if value is not None and value != "" else False for value in values])


def get_keys(d, value):
    return [k for k, v in d.items() if v == value]


def find_nearest_method2(x_data, y_data):
    min_peak = min(y_data)
    peak_index = y_data.index(min_peak)
    length = len(y_data)
    compare_value = float(min_peak) + 3
    min_x = x_data[peak_index]
    target_x_value, target_y_value = "", ""
    for i in range(length):
        result = y_data[i] - compare_value
        if abs(result) < 0.4:  ##### 修改算法，先选出最接近的5个点，然后再看斜率是否符合
            if cal_y_slope(i, y_data) and float(x_data[i]) >= 0:
                target_x_value, target_y_value = x_data[i], y_data[i]
                break
            else:
                continue
    if target_x_value is not None and target_y_value is not None and min_x is not None and min_peak is not None:
        return target_x_value, target_y_value, min_x, min_peak


def find_nearest(array, value):
    array = np.asarray(array)
    idx = (np.abs(array - value)).argmin()
    return idx, array[idx]


# 平滑曲线
def savgol(x_data, y_data):
    plt.plot(x_data, y_data, "k")
    # y_smooth = savgol_filter(y_data, 9, 7, mode="nearest")
    plt.gca().invert_yaxis()
    plt.plot(x_data, y_data, "b")
    plt.xlabel("Current")
    plt.ylabel("Voltage")
    plt.grid(True)
    plt.show()


def get_points_list(start_value, stop_value, points_num):
    if float(stop_value) > float(start_value):
        step = abs((float(stop_value) - float(start_value)) / (float(points_num) - 1))
        data_list = [float(start_value) + i * step for i in range(int(points_num))]
        if data_list:
            return data_list
    elif float(stop_value) < float(start_value):
        step = abs(((float(stop_value)) - float(start_value)) / (
                float(points_num) - 1))
        data_list = [float(start_value) - i * step for i in range(int(points_num))]
        if data_list:
            return data_list
    else:
        data_list = [float(start_value)]
        return data_list


def take_closest(num, collection):
    return min(collection, key=lambda x: abs(x - num))


x_data = get_points_list(0, 3.5, 176)
x_data = get_points_list(0, 2, 101)

y_data1 = [4.707,
           4.686,
           4.666,
           4.662,
           4.642,
           4.642,
           4.555,
           4.557,
           4.482,
           4.374,
           4.349,
           4.303,
           4.204,
           4.171,
           4.059,
           4.014,
           3.915,
           3.785,
           3.737,
           3.687,
           3.533,
           3.427,
           3.335,
           3.216,
           3.176,
           3.114,
           2.957,
           2.902,
           2.801,
           2.731,
           2.677,
           2.617,
           2.464,
           2.427,
           2.414,
           2.375,
           2.278,
           2.248,
           2.298,
           2.151,
           2.214,
           2.209,
           2.227,
           2.278,
           2.318,
           2.341,
           2.464,
           2.542,
           2.646,
           2.773,
           2.971,
           3.117,
           3.301,
           3.481,
           3.776,
           4.082,
           4.4,
           4.849,
           5.251,
           5.683,
           6.228,
           6.791,
           7.589,
           8.273,
           9.268,
           10.357,
           11.668,
           13.207,
           15.204,
           17.893,
           21.89,
           30.164,
           33.738,
           23.101,
           18.63,
           15.553,
           13.242,
           11.383,
           9.992,
           8.775,
           7.62,
           6.786,
           6.012,
           5.308,
           4.644,
           4.171,
           3.66,
           3.286,
           2.979,
           2.672,
           2.418,
           2.311,
           2.148,
           2.156,
           2.196,
           2.183,
           2.31,
           2.569,
           2.788,
           3.162,
           3.568]

y_data2 = [9.182, 9.155, 9.234, 9.308, 9.35, 9.392, 9.471, 9.55, 9.578, 9.66, 9.842, 9.972, 10.12, 10.29, 10.457,
           10.675, 10.903, 11.186, 11.469, 11.678, 12.087, 12.463, 12.849, 13.283, 13.816, 14.343, 15.043, 15.694,
           16.549, 17.409, 18.513, 19.8, 21.394, 23.378, 26.098, 29.999, 38.239, 40.677, 30.61, 25.922, 22.876, 20.565,
           18.704, 17.089, 15.78, 14.562, 13.566, 12.62, 11.804, 11.051, 10.371, 9.678, 9.103, 8.545, 8.025, 7.528,
           7.141, 6.629, 6.287, 5.92, 5.655, 5.39, 5.089, 4.885, 4.662, 4.494, 4.352, 4.267, 4.174, 4.114, 4.097, 4.114,
           4.184, 4.159, 4.312, 4.462, 4.588, 4.929, 5.202, 5.534, 5.896, 6.365, 6.935, 7.519, 8.284, 9.193, 10.263,
           11.441, 12.923, 14.946, 17.598, 21.271, 28.6, 36.169, 23.573, 18.809, 15.71, 13.483, 11.601, 10.14, 8.974]
y_data = [5.183, 5.188, 5.094, 5.071, 5.13, 5.135, 5.147, 5.205, 5.244, 5.25, 5.359, 5.417, 5.477, 5.563, 5.671, 5.767,
          5.846, 6.017, 6.105, 6.279, 6.473, 6.597, 6.798, 6.953, 7.177, 7.393, 7.679, 7.931, 8.194, 8.597, 8.948,
          9.341, 9.78, 10.223, 10.722, 11.304, 11.901, 12.673, 13.543, 14.453, 15.564, 16.901, 18.425, 20.507, 23.212,
          27.47, 35.708, 37.821, 28.057, 23.373, 20.3, 17.997, 16.172, 14.708, 13.401, 12.277, 11.236, 10.289, 9.475,
          8.803, 8.052, 7.439, 6.869, 6.442, 5.846, 5.5, 5.055, 4.722, 4.373, 4.082, 3.775, 3.597, 3.373, 3.241, 3.122,
          2.989, 2.939, 2.877, 2.881, 2.978, 2.884, 3.028, 3.244, 3.417, 3.531, 3.892, 4.277, 4.655, 5.059, 5.596,
          6.253, 6.874, 7.84, 8.868, 10.015, 11.563, 13.573, 15.942, 19.736, 26.618, 38.701]
y_data1 = [13.263,
           13.327,
           13.301,
           13.357,
           13.313,
           13.435,
           13.423,
           13.596,
           13.535,
           13.677,
           13.67,
           13.768,
           13.892,
           13.949,
           14.051,
           14.183,
           14.327,
           14.51,
           14.588,
           14.752,
           14.936,
           15.282,
           15.39,
           15.518,
           15.779,
           16.039,
           16.377,
           16.644,
           16.998,
           17.347,
           17.688,
           17.996,
           18.544,
           18.964,
           19.416,
           20.012,
           20.611,
           21.372,
           22.005,
           22.843,
           23.883,
           25.01,
           26.3,
           27.944,
           29.916,
           32.698,
           36.488,
           42.677,
           43.493,
           36.823,
           32.718,
           29.658,
           27.433,
           25.619,
           24.073,
           22.791,
           21.564,
           20.553,
           19.591,
           18.663,
           17.914,
           17.201,
           16.559,
           15.867,
           15.263,
           14.698,
           14.219,
           13.683,
           13.114,
           12.665,
           12.259,
           11.85,
           11.449,
           10.968,
           10.671,
           10.346,
           9.996,
           9.621,
           9.233,
           8.991,
           8.677,
           8.392,
           8.07,
           7.911,
           7.553,
           7.334,
           7.102,
           6.932,
           6.668,
           6.487,
           6.23,
           6.003,
           5.875,
           5.666,
           5.445,
           5.322,
           5.139,
           4.997,
           4.886,
           4.693,
           4.544,
           4.485,
           4.349,
           4.228,
           4.054,
           3.96,
           3.886,
           3.802,
           3.745,
           3.649,
           3.684,
           3.552,
           3.511,
           3.456,
           3.423,
           3.36,
           3.415,
           3.444,
           3.434,
           3.415,
           3.364,
           3.453,
           3.438,
           3.525,
           3.597,
           3.67,
           3.672,
           3.786,
           3.794,
           3.955,
           4.029,
           4.181,
           4.239,
           4.462,
           4.666,
           4.752,
           4.974,
           5.105,
           5.394,
           5.686,
           5.821,
           6.108,
           6.545,
           6.789,
           7.176,
           7.51,
           7.943,
           8.472,
           8.855,
           9.403,
           9.973,
           10.592,
           11.346,
           12.191,
           13.053,
           14.05,
           15.226,
           16.582,
           18.227,
           20.29,
           23.016,
           26.882,
           34.765,
           40.954,
           29.323,
           24.432,
           21.143,
           18.79,
           17.062,
           15.507,
           14.265,
           13.109,
           12.2,
           11.352,
           10.585,
           9.846,
           ]
#
# savgol(x_data, y_data)
# print(find3db_util(x_data, y_data))

